package utils;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import model.Domain;
import model.Response;
import model.Techticket;
import model.Techticket_;
import model.User;
import dtos.TechticketDTO;
import dtos.TechticketHistoryDTO;
import dtos.UserDTO;

/**
 * Session Bean implementation class TechticketDAO
 * 
 */
@Stateless
@LocalBean
public class TechticketDAO implements TechticketDAORemote {
	@PersistenceContext(unitName = "rmtPersistenceUnit")
	EntityManager em;

	@EJB
	Conv conv;

	/**
	 * Default constructor.
	 */
	public TechticketDAO() {
	}

	/**
	 * Method used to insert techticker
	 * 
	 * @param techticket
	 */
	@Override
	public void insertTechticket(TechticketDTO ticket) {
		Techticket t = em.find(Techticket.class, ticket.getId());
		if (t == null) {
			Techticket t1 = conv.fromEntityTechticketDTO(ticket);
			em.persist(t1);
		} else {
			em.merge(t);
		}
	}

	/**
	 * Method used to get Techticket by id
	 * 
	 * @param id
	 * @return techticket
	 */
	@Override
	public TechticketDTO getTechticket(int id) {
		return conv.fromEntityTechticket(em.find(Techticket.class, id));
	}

	/**
	 * Method used to update Techticket by id
	 * 
	 * @param id
	 */
	@Override
	public void updateTechticket(TechticketDTO ticket) {
		Techticket t = em.find(Techticket.class, ticket.getId());
		if (t == null) {
			Techticket t1 = conv.fromEntityTechticketDTO(ticket);
			em.persist(t1);
		} else {
			t.setStatus(ticket.getStatus());
			t.setResponse(em.find(Response.class, ticket.getIdResponse()));
			em.merge(t);
		}

	}

	/**
	 * Method used to get all Techtickets by id
	 * 
	 * @return list of techtickets
	 */
	@Override
	public List<TechticketDTO> getAllTechtickets() {
		List<TechticketDTO> resultTicketsList = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techticket> cq = cb.createQuery(Techticket.class);
		Root<Techticket> ticket = cq.from(Techticket.class);

		cq.select(ticket).orderBy(cb.desc(ticket.get("status")))
				.orderBy(cb.desc(ticket.get("id")));


		TypedQuery<Techticket> q = em.createQuery(cq);
		List<Techticket> tickets = q.getResultList();
		for (Techticket u : tickets) {
			if (u.getStatus().equals("Processing")
					|| (u.getStatus().equals("Finalized")))
				resultTicketsList.add(conv.fromEntityTechticket(u));
		}
		return resultTicketsList;
	}
	
	/**
	 * Method used to get all Techtickets by id
	 * 
	 * @return list of techtickets
	 */
	@Override
	public List<TechticketDTO> getAllTechticketsTG() {
		List<TechticketDTO> resultTicketsList = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techticket> cq = cb.createQuery(Techticket.class);
		Root<Techticket> ticket = cq.from(Techticket.class);

		cq.select(ticket).orderBy(cb.desc(ticket.get("status")))
				.orderBy(cb.desc(ticket.get("id")));


		TypedQuery<Techticket> q = em.createQuery(cq);
		List<Techticket> tickets = q.getResultList();
		for (Techticket u : tickets) {
			if (u.getStatus().equals("Pending")
					|| (u.getStatus().equals("Responded")))
				resultTicketsList.add(conv.fromEntityTechticket(u));
		}
		return resultTicketsList;
	}

	/**
	 * Method used to get all Techtickets by user id and date
	 * 
	 * @param userDto
	 * @return list of techtickets
	 */
	@Override
	public List<TechticketDTO> getTechticketsByUserIdCurrentMonth(UserDTO ud) {
		User u = conv.fromEntityUserDTO(ud);

		Calendar aMonthAgo = Calendar.getInstance();
		Calendar cal = Calendar.getInstance();

		Date date = new Date();
		aMonthAgo.setTime(date);
		aMonthAgo.add(Calendar.MONTH, -1);

		List<TechticketDTO> resultTicketsList = new ArrayList<>();

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techticket> cq = cb.createQuery(Techticket.class);
		Root<Techticket> ticket = cq.from(Techticket.class);
		cq.select(ticket);
		cq.orderBy(cb.desc(ticket.get(Techticket_.date))).orderBy(cb.desc(ticket.get(Techticket_.id)));

		TypedQuery<Techticket> q = em.createQuery(cq);

		List<Techticket> tickets = q.getResultList();
		for (Techticket t : tickets) {
			Date ticketDate = t.getDate();
			cal.setTime(ticketDate);

			if (t.getUser().getId() == u.getId() && aMonthAgo.before(cal)) {
				resultTicketsList.add(conv.fromEntityTechticket(t));
			}
		}

		return resultTicketsList;
	}

	/**
	 * @param int userId
	 * @return List<TechticketHistoryDTO>
	 * 
	 *         Method used for displaying the tech-tickets sent by a user newer
	 *         than one month (date automatically calculated)
	 */
	@Override
	public List<TechticketHistoryDTO> getTechticketHistoryDTO(int userId) {

		Calendar aMonthAgo = Calendar.getInstance();
		Calendar cal = Calendar.getInstance();

		Date date = new Date();
		aMonthAgo.setTime(date);
		aMonthAgo.add(Calendar.MONTH, -1);

		List<TechticketHistoryDTO> resultTicketsList = new ArrayList<>();

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techticket> cq = cb.createQuery(Techticket.class);
		Root<Techticket> ticket = cq.from(Techticket.class);
		cq.select(ticket);
		cq.orderBy(cb.desc(ticket.get(Techticket_.date)),
				cb.desc(ticket.get(Techticket_.id)));
		TypedQuery<Techticket> q = em.createQuery(cq);

		List<Techticket> tickets = q.getResultList();

		for (Techticket t : tickets) {
			Date ticketDate = t.getDate();
			cal.setTime(ticketDate);

			if (t.getUser().getId() == userId && aMonthAgo.before(cal)) {
				TechticketHistoryDTO tmp = new TechticketHistoryDTO();
				System.out.println("in history " + t.getId());
				tmp.setTicketId(t.getId());
				tmp.setResourceName(t.getTechresource().getName());
				tmp.setProblemType(t.getProblemtype());
				tmp.setTicketDescription(t.getDescription());
				tmp.setStatus(t.getStatus());
				tmp.setTicketDate(t.getDate());
				if (t.getResponse() != null) {
					tmp.setReponseDescription(t.getResponse().getDescription());
					tmp.setResponderName(t.getResponse().getUser().getName());
					tmp.setResponseDate(t.getResponse().getDate());
				} else {
					tmp.setReponseDescription(null);
					tmp.setResponderName(null);
					tmp.setResponseDate(null);
				}
				resultTicketsList.add(tmp);
			}
		}

		return resultTicketsList;
	}

	/**
	 * Method used to delete Techticket
	 */
	@Override
	public void deleteTechticker(TechticketDTO ud) {
		Techticket r1 = em.find(Techticket.class, ud.getId());
		em.createQuery("delete from Techticket where id=:id")
				.setParameter("id", r1.getId()).executeUpdate();
	}

	/**
	 * Method used to get all techtickets by user domain
	 * 
	 * @param user
	 * @return list of techtickets
	 */
	@Override
	public List<TechticketDTO> getTechticketsByUserDomain(UserDTO user) {
		int idUserDomain = user.getIdDomain();
		Domain dom = em.find(Domain.class, idUserDomain);
		System.out.println("id domeniu " + dom.getId());

		List<TechticketDTO> tickets = new ArrayList<>();

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techticket> cq = cb.createQuery(Techticket.class);
		Root<Techticket> resources = cq.from(Techticket.class);
		cq.select(resources);
		cq.orderBy(cb.desc(resources.get(Techticket_.status))).orderBy(
				cb.desc(resources.get(Techticket_.id)));
		List<Techticket> ticketList = em.createQuery(cq).getResultList();
		for (Techticket t : ticketList) {

			User u = t.getUser();
			Domain d = u.getDomain();
			if (d.getId() == dom.getId()
					&& (t.getStatus().equals("Processing") || (t.getStatus()
							.equals("Finalized")))) {
				tickets.add(conv.fromEntityTechticket(t));
			}

		}
		return tickets;
	}

	/**
	 * Method used to get all techtickets by user
	 * 
	 * @param user
	 * @return list of techtickets
	 */
	@Override
	public List<TechticketDTO> getTechticketsByUser(UserDTO user) {
		List<TechticketDTO> tickets = new ArrayList<>();

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techticket> cq = cb.createQuery(Techticket.class);
		Root<Techticket> resources = cq.from(Techticket.class);
		cq.select(resources);

		cq.orderBy(cb.desc(resources.get(Techticket_.status)));
		List<Techticket> ticketList = em.createQuery(cq).getResultList();
		for (Techticket t : ticketList) {
			User u = t.getUser();
			if (u.getId() == user.getId()) {
				tickets.add(conv.fromEntityTechticket(t));
			}
		}
		return tickets;
	}

	/**
	 * Method used to get all techtickets assigned to inactive Office manager
	 * 
	 * @return list of techtickets
	 */
	@Override
	public List<TechticketDTO> getTechticketsByReplacerAdmin() {
		List<TechticketDTO> tickets = new ArrayList<>();

		// get all domains where the Office Manager is replaced by Admin
		List<Domain> inactOMDomain = new ArrayList<>();

		CriteriaBuilder cbUser = em.getCriteriaBuilder();
		CriteriaQuery<User> cqUser = cbUser.createQuery(User.class);
		Root<User> user = cqUser.from(User.class);
		cqUser.select(user);
		TypedQuery<User> q = em.createQuery(cqUser);

		List<User> users = q.getResultList();

		for (User u : users) {
			User replacementUser = u.getUser();
			if (u.getIsactive() == 0 && replacementUser != null
					&& replacementUser.getUsertype().getId() == 1) {
				inactOMDomain.add(u.getDomain());
			}
		}

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techticket> cq = cb.createQuery(Techticket.class);
		Root<Techticket> resources = cq.from(Techticket.class);
		cq.select(resources);

		cq.orderBy(cb.desc(resources.get(Techticket_.status)));
		List<Techticket> ticketList = em.createQuery(cq).getResultList();
		for (Techticket t : ticketList) {
			Domain dom = t.getUser().getDomain();

			for (Domain d : inactOMDomain) {
				if (d.getId() == dom.getId()) {
					tickets.add(conv.fromEntityTechticket(t));
				}
			}
		}
		return tickets;
	}

	/**
	 * Method used to order techtickets by id and status
	 * 
	 * @return list of techtickets
	 */
	@Override
	public List<TechticketDTO> getAllTechticketsOrderedByIdAndStatus() {
		List<TechticketDTO> resultTicketsList = new ArrayList<>();
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Techticket> cq = cb.createQuery(Techticket.class);
		Root<Techticket> ticket = cq.from(Techticket.class);
		cq.select(ticket).orderBy(cb.desc(ticket.get("status")))
				.orderBy(cb.desc(ticket.get("id")));

		TypedQuery<Techticket> q = em.createQuery(cq);
		List<Techticket> tickets = q.getResultList();
		for (Techticket u : tickets) {
			resultTicketsList.add(conv.fromEntityTechticket(u));
		}
		return resultTicketsList;
	}

}
